package ru.msu.phys.cmp.mpga.service.linear;

import org.apache.commons.math3.linear.*;
import ru.msu.phys.cmp.mpga.domain.Point;

public class LinEquationSolver {
	
	private double deltaInvariant;
	private double iInvariant;
	private double dInvariant;

	private double[] solutionAB = new double[2];
	
	
	public LinEquationSolver(Point[] points){
		double[][] array = {
				PointParserService.parse(points[0]),
				PointParserService.parse(points[1]),
				PointParserService.parse(points[2]),
				PointParserService.parse(points[3]),
				PointParserService.parse(points[4]),
		};
		RealMatrix coefficients = 
				new Array2DRowRealMatrix( array, false );
		DecompositionSolver solver = 
				new LUDecomposition(coefficients).getSolver();
		RealVector constants 
			= new ArrayRealVector(array.length,-1);
		RealVector solution = solver.solve(constants);
		double[] arraySolution = solution.toArray();
		double [][] arrayDelta = {   
				{arraySolution[0] , arraySolution[2], arraySolution[3]}, 
				{arraySolution[2] , arraySolution[1], arraySolution[4]}, 
				{arraySolution[3] , arraySolution[4], arraySolution[5]}
		};
		RealMatrix delta = new Array2DRowRealMatrix(arrayDelta,false);

		this.deltaInvariant = (new LUDecomposition(delta)).getDeterminant();
		this.dInvariant = arraySolution[0]*arraySolution[1] - 
				arraySolution[3]*arraySolution[3];
		this.iInvariant = arraySolution[0] + arraySolution[1];
		
		double a = Math.sqrt( 2 / ( iInvariant + 
				Math.sqrt(iInvariant*iInvariant - 4*dInvariant)));
		double b = 1 / ( a * Math.sqrt(dInvariant));
		solutionAB[0] = a;
		solutionAB[1] = b;
		
	}
	
	
	public double getDeltaInvariant() {
		return deltaInvariant;
	}
	
	
	public double getiInvariant() {
		return iInvariant;
	}
	
	
	public double getdInvariant() {
		return dInvariant;
	}
	
	
	public double[] getSolution() {
		return solutionAB;
	}

	
}

class PointParserService {
	static double[] parse(Point point){
		double [] result = {
				point.getX()*point.getX(),
				point.getY()*point.getY(),
				2*point.getX()*point.getY(),
				2*point.getX(),
				2*point.getY(),
				1
		};
		return result;
	}
}